Analysis and visualisation of spatial transcriptomics data. Generally followed this Seurat workflow.

Load libraries

library(Seurat)
library(ggplot2)
library(patchwork)
library(dplyr)
library(UCell)
#library(ggpubr)

Load merged liver slices and set identity

sobj <- readRDS("../spatial/merged_spatial_sobj.RDS")
Idents(sobj) <- "SCT_snn_res.0.2"

Visualise clusters on spatial plot

plot1 <- SpatialDimPlot(sobj, alpha = 0.7, images = 'slice1') & NoLegend()
plot2 <- SpatialDimPlot(sobj, alpha = 0.7, images = 'slice1.1') +
  labs(fill = "Cluster")
plot1 + plot2
pdf("./figures/spatial/merged_dimPlot_UMAP.pdf")
plot1 + plot2
dev.off()
png 
  2 

Visualise features on spatial plot

Look at other genes

gene <- "Saa2;Saa1-1"
plot1 <- SpatialFeaturePlot(sobj, features = gene, images = 'slice1') & NoLegend()
plot2 <- SpatialFeaturePlot(sobj, features = gene, images = 'slice1.1') & NoLegend()
print(plot1 + plot2)

Calculate markers

all.markers <- FindAllMarkers(sobj, 
                              only.pos = TRUE, 
                              min.pct = 0.25, 
                              logfc.threshold = 0.25,
                              recorrect_umi = FALSE)
Calculating cluster 0

  |                                                  | 0 % ~calculating  
  |+++                                               | 4 % ~00s          
  |+++++                                             | 9 % ~00s          
  |+++++++                                           | 13% ~00s          
  |+++++++++                                         | 17% ~00s          
  |+++++++++++                                       | 22% ~00s          
  |++++++++++++++                                    | 26% ~00s          
  |++++++++++++++++                                  | 30% ~00s          
  |++++++++++++++++++                                | 35% ~00s          
  |++++++++++++++++++++                              | 39% ~00s          
  |++++++++++++++++++++++                            | 43% ~00s          
  |++++++++++++++++++++++++                          | 48% ~00s          
  |+++++++++++++++++++++++++++                       | 52% ~00s          
  |+++++++++++++++++++++++++++++                     | 57% ~00s          
  |+++++++++++++++++++++++++++++++                   | 61% ~00s          
  |+++++++++++++++++++++++++++++++++                 | 65% ~00s          
  |+++++++++++++++++++++++++++++++++++               | 70% ~00s          
  |+++++++++++++++++++++++++++++++++++++             | 74% ~00s          
  |++++++++++++++++++++++++++++++++++++++++          | 78% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++        | 83% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++++      | 87% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++++++    | 91% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++++++++  | 96% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++++++++++| 100% elapsed=00s  
Calculating cluster 1

  |                                                  | 0 % ~calculating  
  |+++                                               | 4 % ~00s          
  |+++++                                             | 8 % ~00s          
  |+++++++                                           | 12% ~00s          
  |+++++++++                                         | 17% ~00s          
  |+++++++++++                                       | 21% ~00s          
  |+++++++++++++                                     | 25% ~00s          
  |+++++++++++++++                                   | 29% ~00s          
  |+++++++++++++++++                                 | 33% ~00s          
  |+++++++++++++++++++                               | 38% ~00s          
  |+++++++++++++++++++++                             | 42% ~00s          
  |+++++++++++++++++++++++                           | 46% ~00s          
  |+++++++++++++++++++++++++                         | 50% ~00s          
  |++++++++++++++++++++++++++++                      | 54% ~00s          
  |++++++++++++++++++++++++++++++                    | 58% ~00s          
  |++++++++++++++++++++++++++++++++                  | 62% ~00s          
  |++++++++++++++++++++++++++++++++++                | 67% ~00s          
  |++++++++++++++++++++++++++++++++++++              | 71% ~00s          
  |++++++++++++++++++++++++++++++++++++++            | 75% ~00s          
  |++++++++++++++++++++++++++++++++++++++++          | 79% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++        | 83% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++++      | 88% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++++++    | 92% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++++++++  | 96% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++++++++++| 100% elapsed=00s  
Calculating cluster 2

  |                                                  | 0 % ~calculating  
  |++                                                | 3 % ~00s          
  |++++                                              | 6 % ~00s          
  |+++++                                             | 10% ~00s          
  |+++++++                                           | 13% ~00s          
  |+++++++++                                         | 16% ~00s          
  |++++++++++                                        | 19% ~00s          
  |++++++++++++                                      | 23% ~00s          
  |+++++++++++++                                     | 26% ~00s          
  |+++++++++++++++                                   | 29% ~00s          
  |+++++++++++++++++                                 | 32% ~00s          
  |++++++++++++++++++                                | 35% ~00s          
  |++++++++++++++++++++                              | 39% ~00s          
  |+++++++++++++++++++++                             | 42% ~00s          
  |+++++++++++++++++++++++                           | 45% ~00s          
  |+++++++++++++++++++++++++                         | 48% ~00s          
  |++++++++++++++++++++++++++                        | 52% ~00s          
  |++++++++++++++++++++++++++++                      | 55% ~00s          
  |++++++++++++++++++++++++++++++                    | 58% ~00s          
  |+++++++++++++++++++++++++++++++                   | 61% ~00s          
  |+++++++++++++++++++++++++++++++++                 | 65% ~00s          
  |++++++++++++++++++++++++++++++++++                | 68% ~00s          
  |++++++++++++++++++++++++++++++++++++              | 71% ~00s          
  |++++++++++++++++++++++++++++++++++++++            | 74% ~00s          
  |+++++++++++++++++++++++++++++++++++++++           | 77% ~00s          
  |+++++++++++++++++++++++++++++++++++++++++         | 81% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++        | 84% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++++      | 87% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++++++    | 90% ~00s          
  |+++++++++++++++++++++++++++++++++++++++++++++++   | 94% ~00s          
  |+++++++++++++++++++++++++++++++++++++++++++++++++ | 97% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++++++++++| 100% elapsed=00s  
Calculating cluster 3

  |                                                  | 0 % ~calculating  
  |+++                                               | 5 % ~00s          
  |+++++                                             | 9 % ~00s          
  |+++++++                                           | 14% ~00s          
  |++++++++++                                        | 18% ~00s          
  |++++++++++++                                      | 23% ~00s          
  |++++++++++++++                                    | 27% ~00s          
  |++++++++++++++++                                  | 32% ~00s          
  |+++++++++++++++++++                               | 36% ~00s          
  |+++++++++++++++++++++                             | 41% ~00s          
  |+++++++++++++++++++++++                           | 45% ~00s          
  |+++++++++++++++++++++++++                         | 50% ~00s          
  |++++++++++++++++++++++++++++                      | 55% ~00s          
  |++++++++++++++++++++++++++++++                    | 59% ~00s          
  |++++++++++++++++++++++++++++++++                  | 64% ~00s          
  |+++++++++++++++++++++++++++++++++++               | 68% ~00s          
  |+++++++++++++++++++++++++++++++++++++             | 73% ~00s          
  |+++++++++++++++++++++++++++++++++++++++           | 77% ~00s          
  |+++++++++++++++++++++++++++++++++++++++++         | 82% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++++      | 86% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++++++    | 91% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++++++++  | 95% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++++++++++| 100% elapsed=00s  
Calculating cluster 4

  |                                                  | 0 % ~calculating  
  |+                                                 | 1 % ~01s          
  |++                                                | 3 % ~01s          
  |+++                                               | 4 % ~01s          
  |+++                                               | 5 % ~01s          
  |++++                                              | 7 % ~01s          
  |+++++                                             | 8 % ~01s          
  |+++++                                             | 10% ~01s          
  |++++++                                            | 11% ~01s          
  |+++++++                                           | 12% ~01s          
  |+++++++                                           | 14% ~01s          
  |++++++++                                          | 15% ~01s          
  |+++++++++                                         | 16% ~01s          
  |+++++++++                                         | 18% ~01s          
  |++++++++++                                        | 19% ~00s          
  |+++++++++++                                       | 21% ~00s          
  |+++++++++++                                       | 22% ~00s          
  |++++++++++++                                      | 23% ~00s          
  |+++++++++++++                                     | 25% ~00s          
  |++++++++++++++                                    | 26% ~00s          
  |++++++++++++++                                    | 27% ~00s          
  |+++++++++++++++                                   | 29% ~00s          
  |++++++++++++++++                                  | 30% ~00s          
  |++++++++++++++++                                  | 32% ~00s          
  |+++++++++++++++++                                 | 33% ~00s          
  |++++++++++++++++++                                | 34% ~00s          
  |++++++++++++++++++                                | 36% ~00s          
  |+++++++++++++++++++                               | 37% ~00s          
  |++++++++++++++++++++                              | 38% ~00s          
  |++++++++++++++++++++                              | 40% ~00s          
  |+++++++++++++++++++++                             | 41% ~00s          
  |++++++++++++++++++++++                            | 42% ~00s          
  |++++++++++++++++++++++                            | 44% ~00s          
  |+++++++++++++++++++++++                           | 45% ~00s          
  |++++++++++++++++++++++++                          | 47% ~00s          
  |++++++++++++++++++++++++                          | 48% ~00s          
  |+++++++++++++++++++++++++                         | 49% ~00s          
  |++++++++++++++++++++++++++                        | 51% ~00s          
  |+++++++++++++++++++++++++++                       | 52% ~00s          
  |+++++++++++++++++++++++++++                       | 53% ~00s          
  |++++++++++++++++++++++++++++                      | 55% ~00s          
  |+++++++++++++++++++++++++++++                     | 56% ~00s          
  |+++++++++++++++++++++++++++++                     | 58% ~00s          
  |++++++++++++++++++++++++++++++                    | 59% ~00s          
  |+++++++++++++++++++++++++++++++                   | 60% ~00s          
  |+++++++++++++++++++++++++++++++                   | 62% ~00s          
  |++++++++++++++++++++++++++++++++                  | 63% ~00s          
  |+++++++++++++++++++++++++++++++++                 | 64% ~00s          
  |+++++++++++++++++++++++++++++++++                 | 66% ~00s          
  |++++++++++++++++++++++++++++++++++                | 67% ~00s          
  |+++++++++++++++++++++++++++++++++++               | 68% ~00s          
  |+++++++++++++++++++++++++++++++++++               | 70% ~00s          
  |++++++++++++++++++++++++++++++++++++              | 71% ~00s          
  |+++++++++++++++++++++++++++++++++++++             | 73% ~00s          
  |+++++++++++++++++++++++++++++++++++++             | 74% ~00s          
  |++++++++++++++++++++++++++++++++++++++            | 75% ~00s          
  |+++++++++++++++++++++++++++++++++++++++           | 77% ~00s          
  |++++++++++++++++++++++++++++++++++++++++          | 78% ~00s          
  |++++++++++++++++++++++++++++++++++++++++          | 79% ~00s          
  |+++++++++++++++++++++++++++++++++++++++++         | 81% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++        | 82% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++        | 84% ~00s          
  |+++++++++++++++++++++++++++++++++++++++++++       | 85% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++++      | 86% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++++      | 88% ~00s          
  |+++++++++++++++++++++++++++++++++++++++++++++     | 89% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++++++    | 90% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++++++    | 92% ~00s          
  |+++++++++++++++++++++++++++++++++++++++++++++++   | 93% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++++++++  | 95% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++++++++  | 96% ~00s          
  |+++++++++++++++++++++++++++++++++++++++++++++++++ | 97% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++++++++++| 99% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++++++++++| 100% elapsed=01s  
top.markers <- all.markers %>% group_by(cluster) %>% top_n(n = 10, wt = avg_log2FC)
top.markers

Create zonation scores using top 10 genes from periportal and pericentral clusters

# Compare clusters 0 and 1
markers <- FindMarkers(sobj,
                       ident.1 = '0',
                       ident.2 = '1',
                       only.pos = FALSE,
                       min.pct = 0.25,
                       logfc.threshold = 0.25,
                       recorrect_umi = FALSE)

  |                                                  | 0 % ~calculating  
  |+                                                 | 1 % ~01s          
  |++                                                | 3 % ~01s          
  |++                                                | 4 % ~01s          
  |+++                                               | 5 % ~01s          
  |++++                                              | 6 % ~01s          
  |++++                                              | 8 % ~01s          
  |+++++                                             | 9 % ~01s          
  |++++++                                            | 10% ~01s          
  |++++++                                            | 11% ~01s          
  |+++++++                                           | 13% ~01s          
  |+++++++                                           | 14% ~01s          
  |++++++++                                          | 15% ~01s          
  |+++++++++                                         | 16% ~01s          
  |+++++++++                                         | 18% ~01s          
  |++++++++++                                        | 19% ~01s          
  |+++++++++++                                       | 20% ~01s          
  |+++++++++++                                       | 22% ~01s          
  |++++++++++++                                      | 23% ~01s          
  |+++++++++++++                                     | 24% ~01s          
  |+++++++++++++                                     | 25% ~01s          
  |++++++++++++++                                    | 27% ~01s          
  |++++++++++++++                                    | 28% ~01s          
  |+++++++++++++++                                   | 29% ~01s          
  |++++++++++++++++                                  | 30% ~01s          
  |++++++++++++++++                                  | 32% ~01s          
  |+++++++++++++++++                                 | 33% ~01s          
  |++++++++++++++++++                                | 34% ~01s          
  |++++++++++++++++++                                | 35% ~01s          
  |+++++++++++++++++++                               | 37% ~01s          
  |+++++++++++++++++++                               | 38% ~01s          
  |++++++++++++++++++++                              | 39% ~01s          
  |+++++++++++++++++++++                             | 41% ~01s          
  |+++++++++++++++++++++                             | 42% ~01s          
  |++++++++++++++++++++++                            | 43% ~01s          
  |+++++++++++++++++++++++                           | 44% ~01s          
  |+++++++++++++++++++++++                           | 46% ~01s          
  |++++++++++++++++++++++++                          | 47% ~01s          
  |+++++++++++++++++++++++++                         | 48% ~01s          
  |+++++++++++++++++++++++++                         | 49% ~01s          
  |++++++++++++++++++++++++++                        | 51% ~01s          
  |++++++++++++++++++++++++++                        | 52% ~01s          
  |+++++++++++++++++++++++++++                       | 53% ~01s          
  |++++++++++++++++++++++++++++                      | 54% ~01s          
  |++++++++++++++++++++++++++++                      | 56% ~01s          
  |+++++++++++++++++++++++++++++                     | 57% ~01s          
  |++++++++++++++++++++++++++++++                    | 58% ~01s          
  |++++++++++++++++++++++++++++++                    | 59% ~01s          
  |+++++++++++++++++++++++++++++++                   | 61% ~00s          
  |++++++++++++++++++++++++++++++++                  | 62% ~00s          
  |++++++++++++++++++++++++++++++++                  | 63% ~00s          
  |+++++++++++++++++++++++++++++++++                 | 65% ~00s          
  |+++++++++++++++++++++++++++++++++                 | 66% ~00s          
  |++++++++++++++++++++++++++++++++++                | 67% ~00s          
  |+++++++++++++++++++++++++++++++++++               | 68% ~00s          
  |+++++++++++++++++++++++++++++++++++               | 70% ~00s          
  |++++++++++++++++++++++++++++++++++++              | 71% ~00s          
  |+++++++++++++++++++++++++++++++++++++             | 72% ~00s          
  |+++++++++++++++++++++++++++++++++++++             | 73% ~00s          
  |++++++++++++++++++++++++++++++++++++++            | 75% ~00s          
  |++++++++++++++++++++++++++++++++++++++            | 76% ~00s          
  |+++++++++++++++++++++++++++++++++++++++           | 77% ~00s          
  |++++++++++++++++++++++++++++++++++++++++          | 78% ~00s          
  |++++++++++++++++++++++++++++++++++++++++          | 80% ~00s          
  |+++++++++++++++++++++++++++++++++++++++++         | 81% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++        | 82% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++        | 84% ~00s          
  |+++++++++++++++++++++++++++++++++++++++++++       | 85% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++++      | 86% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++++      | 87% ~00s          
  |+++++++++++++++++++++++++++++++++++++++++++++     | 89% ~00s          
  |+++++++++++++++++++++++++++++++++++++++++++++     | 90% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++++++    | 91% ~00s          
  |+++++++++++++++++++++++++++++++++++++++++++++++   | 92% ~00s          
  |+++++++++++++++++++++++++++++++++++++++++++++++   | 94% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++++++++  | 95% ~00s          
  |+++++++++++++++++++++++++++++++++++++++++++++++++ | 96% ~00s          
  |+++++++++++++++++++++++++++++++++++++++++++++++++ | 97% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++++++++++| 99% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++++++++++| 100% elapsed=01s  
# Remove mikado genes
markers <- markers[grep("mikado", rownames(markers), invert = TRUE),]
# Get top 30 periportal genes
pp_genes <- rownames(markers[markers$avg_log2FC > 0,])[1:10]
pp_genes
 [1] "Saa2;Saa1-1"                   "HAMP"                         
 [3] "APOA1"                         "APOC2"                        
 [5] "CRYL1"                         "AMY1A;AMY1C;AMY1B;AMY2A;AMY2B"
 [7] "MT-ATP6"                       "UROC1"                        
 [9] "APOA2"                         "MT-CO3"                       
# Get top 30 pericentral genes
cv_genes <- rownames(markers[markers$avg_log2FC < 0,])[1:10]
cv_genes
 [1] "FETUB"       "HMGCS1"      "CYP2E1"      "GLUD1;GLUD2" "CYP1A2"      "RGN"        
 [7] "INMT"        "COMT"        "FDPS"        "SPR-1"      

Format for UCell

mySigs <- list()
mySigs$Periportal <- pp_genes
mySigs$Pericentral <- cv_genes
mySigs
$Periportal
 [1] "Saa2;Saa1-1"                   "HAMP"                         
 [3] "APOA1"                         "APOC2"                        
 [5] "CRYL1"                         "AMY1A;AMY1C;AMY1B;AMY2A;AMY2B"
 [7] "MT-ATP6"                       "UROC1"                        
 [9] "APOA2"                         "MT-CO3"                       

$Pericentral
 [1] "FETUB"       "HMGCS1"      "CYP2E1"      "GLUD1;GLUD2" "CYP1A2"      "RGN"        
 [7] "INMT"        "COMT"        "FDPS"        "SPR-1"      

Add these as gene signatures

sobj <- AddModuleScore_UCell(sobj, features = mySigs, assay = "SCT")
signature.names <- paste0(names(mySigs), "_UCell")
VlnPlot(sobj, features = signature.names, group.by = "SCT_snn_res.0.2")

SpatialFeaturePlot(sobj,
                   features = signature.names,
                   images = 'slice1')

SpatialFeaturePlot(sobj,
                   features = signature.names,
                   images = 'slice1.1')

Create figures of spatial plots with signatures

plot1 <- SpatialFeaturePlot(sobj,
                            features = "Periportal_UCell",
                            images = 'slice1')
plot2 <- SpatialFeaturePlot(sobj,
                            features = "Periportal_UCell",
                            images = 'slice1.1')
pdf("./figures/spatial/periportalSig_spatial_UCell.pdf")
plot1 + plot2
dev.off()
null device 
          1 
plot1 <- SpatialFeaturePlot(sobj,
                            features = "Pericentral_UCell",
                            images = 'slice1')
plot2 <- SpatialFeaturePlot(sobj,
                            features = "Pericentral_UCell",
                            images = 'slice1.1')
pdf("./figures/spatial/pericentralSig_spatial_UCell.pdf")
plot1 + plot2
dev.off()
null device 
          1 

Create heatmap with signature genes

Correlate UMAP zonation scores with gene expression

FeaturePlot(sobj, features = c("WNT2", "Pericentral_UCell"), blend = TRUE)
Warning: Could not find WNT2 in the default search locations, found in ‘Spatial’ assay instead

FeatureScatter(sobj, feature1 = "WNT2", feature2 = "Pericentral_UCell")
Warning: Could not find WNT2 in the default search locations, found in ‘Spatial’ assay instead

Calculate Z-score for each gene for CV and PP signatures

zscore = (sobj@assays$SCT@scale.data['CYP2E1',] - sobj$Pericentral_UCell)/sd(sobj$Pericentral_UCell)
sobj$cyp2e1_zscore <- scale(zscore)
SpatialFeaturePlot(sobj, features = 'cyp2e1_zscore', images = 'slice1')

Try with RSPO3

zscore = (sobj@assays$SCT@scale.data['RSPO3',] - sobj$Pericentral_UCell)/sd(sobj$Pericentral_UCell)
sobj$rspo3_zscore <- scale(zscore)
SpatialFeaturePlot(sobj, features = 'rspo3_zscore', images = 'slice1')

Correlate all genes with CV and PP signatures

cv_cor <- apply(sobj@assays$SCT@counts, 1, function (x) cor(x, y = sobj$Pericentral_UCell,
                                                                method = "spearman"))
Warning: the standard deviation is zero
head(sort(cv_cor, decreasing = TRUE))
    FETUB    CYP2E1    HMGCS1    CYP1A2       RGN      COMT 
0.7660823 0.7393928 0.7129019 0.6500996 0.6442300 0.6336671 
pp_cor <- apply(sobj@assays$SCT@counts, 1, function (x) cor(x, y = sobj$Periportal_UCell,
                                                                method = "spearman"))
Warning: the standard deviation is zero
head(sort(pp_cor, decreasing = TRUE))
                         HAMP                   Saa2;Saa1-1 AMY1A;AMY1C;AMY1B;AMY2A;AMY2B 
                    0.7191834                     0.6434277                     0.5996466 
                        APOA1                         CRYL1                         APOC2 
                    0.5084247                     0.5080673                     0.5008200 

Write table

spatial_cors <- cbind(cv_cor, pp_cor)
write.table(spatial_cors,
            file = "./figures/spatial/spatial_gene_correlations.tsv",
            quote = FALSE,
            sep = "\t",
            row.names = TRUE,
            col.names = TRUE)

Save object if needed

saveRDS(sobj,
        file = "../spatial/merged_spatial_sobj.RDS")
LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKQW5hbHlzaXMgYW5kIHZpc3VhbGlzYXRpb24gb2Ygc3BhdGlhbCB0cmFuc2NyaXB0b21pY3MgZGF0YS4gR2VuZXJhbGx5IGZvbGxvd2VkIFt0aGlzIFNldXJhdCB3b3JrZmxvd10oaHR0cHM6Ly9zYXRpamFsYWIub3JnL3NldXJhdC9hcmNoaXZlL3YzLjIvc3BhdGlhbF92aWduZXR0ZS5odG1sKS4KCkxvYWQgbGlicmFyaWVzCgpgYGB7cn0KbGlicmFyeShTZXVyYXQpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShwYXRjaHdvcmspCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoVUNlbGwpCiNsaWJyYXJ5KGdncHVicikKYGBgCgpMb2FkIG1lcmdlZCBsaXZlciBzbGljZXMgYW5kIHNldCBpZGVudGl0eQoKYGBge3J9CnNvYmogPC0gcmVhZFJEUygiLi4vc3BhdGlhbC9tZXJnZWRfc3BhdGlhbF9zb2JqLlJEUyIpCklkZW50cyhzb2JqKSA8LSAiU0NUX3Nubl9yZXMuMC4yIgpgYGAKClZpc3VhbGlzZSBjbHVzdGVycyBvbiBzcGF0aWFsIHBsb3QKCmBgYHtyfQpwbG90MSA8LSBTcGF0aWFsRGltUGxvdChzb2JqLCBhbHBoYSA9IDAuNywgaW1hZ2VzID0gJ3NsaWNlMScpICYgTm9MZWdlbmQoKQpwbG90MiA8LSBTcGF0aWFsRGltUGxvdChzb2JqLCBhbHBoYSA9IDAuNywgaW1hZ2VzID0gJ3NsaWNlMS4xJykgKwogIGxhYnMoZmlsbCA9ICJDbHVzdGVyIikKcGxvdDEgKyBwbG90MgpwZGYoIi4vZmlndXJlcy9zcGF0aWFsL21lcmdlZF9kaW1QbG90X1VNQVAucGRmIikKcGxvdDEgKyBwbG90MgpkZXYub2ZmKCkKYGBgCgpWaXN1YWxpc2UgZmVhdHVyZXMgb24gc3BhdGlhbCBwbG90CgpgYGB7cn0KZ2VuZXMgPC0gYygiQ1lQMkUxIiwiRkVUVUIiLCJITUdDUzEiLCJBUE9DMiIsIlNhYTI7U2FhMS0xIiwiSEFNUCIpCmZvciAoZ2VuZSBpbiBnZW5lcykgewogIHBsb3QxIDwtIFNwYXRpYWxGZWF0dXJlUGxvdChzb2JqLCBmZWF0dXJlcyA9IGdlbmUsIGltYWdlcyA9ICdzbGljZTEnKSAmIE5vTGVnZW5kKCkKICBwbG90MiA8LSBTcGF0aWFsRmVhdHVyZVBsb3Qoc29iaiwgZmVhdHVyZXMgPSBnZW5lLCBpbWFnZXMgPSAnc2xpY2UxLjEnKSAmIE5vTGVnZW5kKCkKICBwcmludChwbG90MSArIHBsb3QyKQogIHBkZihwYXN0ZSgiLi9maWd1cmVzL3NwYXRpYWwvbWVyZ2VkX3NwYXRpYWxQbG90XyIsIGdlbmUsICIucGRmIiwgc2VwID0gIiIpKQogIHByaW50KHBsb3QxICsgcGxvdDIpCiAgZGV2Lm9mZigpCn0KYGBgCgpMb29rIGF0IG90aGVyIGdlbmVzCgpgYGB7cn0KZ2VuZSA8LSAiU2FhMjtTYWExLTEiCnBsb3QxIDwtIFNwYXRpYWxGZWF0dXJlUGxvdChzb2JqLCBmZWF0dXJlcyA9IGdlbmUsIGltYWdlcyA9ICdzbGljZTEnKSAmIE5vTGVnZW5kKCkKcGxvdDIgPC0gU3BhdGlhbEZlYXR1cmVQbG90KHNvYmosIGZlYXR1cmVzID0gZ2VuZSwgaW1hZ2VzID0gJ3NsaWNlMS4xJykgJiBOb0xlZ2VuZCgpCnByaW50KHBsb3QxICsgcGxvdDIpCmBgYAoKCkNhbGN1bGF0ZSBtYXJrZXJzCgpgYGB7cn0KYWxsLm1hcmtlcnMgPC0gRmluZEFsbE1hcmtlcnMoc29iaiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9ubHkucG9zID0gVFJVRSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1pbi5wY3QgPSAwLjI1LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9nZmMudGhyZXNob2xkID0gMC4yNSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVjb3JyZWN0X3VtaSA9IEZBTFNFKQp0b3AubWFya2VycyA8LSBhbGwubWFya2VycyAlPiUgZ3JvdXBfYnkoY2x1c3RlcikgJT4lIHRvcF9uKG4gPSAxMCwgd3QgPSBhdmdfbG9nMkZDKQp0b3AubWFya2Vycwp3cml0ZS50YWJsZShhbGwubWFya2VycywKICAgICAgICAgICAgZmlsZSA9ICIuL2ZpZ3VyZXMvc3BhdGlhbC9tZXJnZWRfc3BhdGlhbF9tYXJrZXJzLnRzdiIsCiAgICAgICAgICAgIHNlcCA9ICJcdCIsCiAgICAgICAgICAgIHF1b3RlID0gRkFMU0UsCiAgICAgICAgICAgIHJvdy5uYW1lcyA9IEZBTFNFKQpgYGAKCkNyZWF0ZSB6b25hdGlvbiBzY29yZXMgdXNpbmcgdG9wIDEwIGdlbmVzIGZyb20gcGVyaXBvcnRhbCBhbmQgcGVyaWNlbnRyYWwgY2x1c3RlcnMKCmBgYHtyfQojIENvbXBhcmUgY2x1c3RlcnMgMCBhbmQgMQptYXJrZXJzIDwtIEZpbmRNYXJrZXJzKHNvYmosCiAgICAgICAgICAgICAgICAgICAgICAgaWRlbnQuMSA9ICcwJywKICAgICAgICAgICAgICAgICAgICAgICBpZGVudC4yID0gJzEnLAogICAgICAgICAgICAgICAgICAgICAgIG9ubHkucG9zID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICAgbWluLnBjdCA9IDAuMjUsCiAgICAgICAgICAgICAgICAgICAgICAgbG9nZmMudGhyZXNob2xkID0gMC4yNSwKICAgICAgICAgICAgICAgICAgICAgICByZWNvcnJlY3RfdW1pID0gRkFMU0UpCiMgUmVtb3ZlIG1pa2FkbyBnZW5lcwptYXJrZXJzIDwtIG1hcmtlcnNbZ3JlcCgibWlrYWRvIiwgcm93bmFtZXMobWFya2VycyksIGludmVydCA9IFRSVUUpLF0KIyBHZXQgdG9wIDMwIHBlcmlwb3J0YWwgZ2VuZXMKcHBfZ2VuZXMgPC0gcm93bmFtZXMobWFya2Vyc1ttYXJrZXJzJGF2Z19sb2cyRkMgPiAwLF0pWzE6MTBdCnBwX2dlbmVzCiMgR2V0IHRvcCAzMCBwZXJpY2VudHJhbCBnZW5lcwpjdl9nZW5lcyA8LSByb3duYW1lcyhtYXJrZXJzW21hcmtlcnMkYXZnX2xvZzJGQyA8IDAsXSlbMToxMF0KY3ZfZ2VuZXMKYGBgCgpGb3JtYXQgZm9yIFVDZWxsCgpgYGB7cn0KbXlTaWdzIDwtIGxpc3QoKQpteVNpZ3MkUGVyaXBvcnRhbCA8LSBwcF9nZW5lcwpteVNpZ3MkUGVyaWNlbnRyYWwgPC0gY3ZfZ2VuZXMKbXlTaWdzCmBgYAoKCkFkZCB0aGVzZSBhcyBnZW5lIHNpZ25hdHVyZXMKCmBgYHtyfQpzb2JqIDwtIEFkZE1vZHVsZVNjb3JlX1VDZWxsKHNvYmosIGZlYXR1cmVzID0gbXlTaWdzLCBhc3NheSA9ICJTQ1QiKQpzaWduYXR1cmUubmFtZXMgPC0gcGFzdGUwKG5hbWVzKG15U2lncyksICJfVUNlbGwiKQpWbG5QbG90KHNvYmosIGZlYXR1cmVzID0gc2lnbmF0dXJlLm5hbWVzLCBncm91cC5ieSA9ICJTQ1Rfc25uX3Jlcy4wLjIiKQpTcGF0aWFsRmVhdHVyZVBsb3Qoc29iaiwKICAgICAgICAgICAgICAgICAgIGZlYXR1cmVzID0gc2lnbmF0dXJlLm5hbWVzLAogICAgICAgICAgICAgICAgICAgaW1hZ2VzID0gJ3NsaWNlMScpClNwYXRpYWxGZWF0dXJlUGxvdChzb2JqLAogICAgICAgICAgICAgICAgICAgZmVhdHVyZXMgPSBzaWduYXR1cmUubmFtZXMsCiAgICAgICAgICAgICAgICAgICBpbWFnZXMgPSAnc2xpY2UxLjEnKQpgYGAKCkNyZWF0ZSBmaWd1cmVzIG9mIHNwYXRpYWwgcGxvdHMgd2l0aCBzaWduYXR1cmVzCgpgYGB7cn0KcGxvdDEgPC0gU3BhdGlhbEZlYXR1cmVQbG90KHNvYmosCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBmZWF0dXJlcyA9ICJQZXJpcG9ydGFsX1VDZWxsIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGltYWdlcyA9ICdzbGljZTEnKQpwbG90MiA8LSBTcGF0aWFsRmVhdHVyZVBsb3Qoc29iaiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZlYXR1cmVzID0gIlBlcmlwb3J0YWxfVUNlbGwiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgaW1hZ2VzID0gJ3NsaWNlMS4xJykKcGRmKCIuL2ZpZ3VyZXMvc3BhdGlhbC9wZXJpcG9ydGFsU2lnX3NwYXRpYWxfVUNlbGwucGRmIikKcGxvdDEgKyBwbG90MgpkZXYub2ZmKCkKYGBgCgpgYGB7cn0KcGxvdDEgPC0gU3BhdGlhbEZlYXR1cmVQbG90KHNvYmosCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBmZWF0dXJlcyA9ICJQZXJpY2VudHJhbF9VQ2VsbCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbWFnZXMgPSAnc2xpY2UxJykKcGxvdDIgPC0gU3BhdGlhbEZlYXR1cmVQbG90KHNvYmosCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBmZWF0dXJlcyA9ICJQZXJpY2VudHJhbF9VQ2VsbCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbWFnZXMgPSAnc2xpY2UxLjEnKQpwZGYoIi4vZmlndXJlcy9zcGF0aWFsL3BlcmljZW50cmFsU2lnX3NwYXRpYWxfVUNlbGwucGRmIikKcGxvdDEgKyBwbG90MgpkZXYub2ZmKCkKYGBgCgpDcmVhdGUgaGVhdG1hcCB3aXRoIHNpZ25hdHVyZSBnZW5lcwoKYGBge3J9CnBsb3QgPC0gRG9IZWF0bWFwKHNvYmosCiAgICAgICAgICAgICAgICAgIGZlYXR1cmVzID0gYyhwcF9nZW5lcywgY3ZfZ2VuZXMpLAogICAgICAgICAgICAgICAgICBhbmdsZSA9IDAsCiAgICAgICAgICAgICAgICAgIHNpemUgPSAzKQpwbG90CnBkZigiLi9maWd1cmVzL3NwYXRpYWwvem9uZVNpZ3NfYnlDbHVzdF9oZWF0bWFwLnBkZiIpCnBsb3QKZGV2Lm9mZigpCmBgYAoKQ29ycmVsYXRlIFVNQVAgem9uYXRpb24gc2NvcmVzIHdpdGggZ2VuZSBleHByZXNzaW9uCgpgYGB7cn0KRmVhdHVyZVBsb3Qoc29iaiwgZmVhdHVyZXMgPSBjKCJXTlQyIiwgIlBlcmljZW50cmFsX1VDZWxsIiksIGJsZW5kID0gVFJVRSkKRmVhdHVyZVNjYXR0ZXIoc29iaiwgZmVhdHVyZTEgPSAiV05UMiIsIGZlYXR1cmUyID0gIlBlcmljZW50cmFsX1VDZWxsIikKYGBgCgpDYWxjdWxhdGUgWi1zY29yZSBmb3IgZWFjaCBnZW5lIGZvciBDViBhbmQgUFAgc2lnbmF0dXJlcwoKYGBge3J9CnpzY29yZSA9IChzb2JqQGFzc2F5cyRTQ1RAc2NhbGUuZGF0YVsnQ1lQMkUxJyxdIC0gc29iaiRQZXJpY2VudHJhbF9VQ2VsbCkvc2Qoc29iaiRQZXJpY2VudHJhbF9VQ2VsbCkKc29iaiRjeXAyZTFfenNjb3JlIDwtIHNjYWxlKHpzY29yZSkKU3BhdGlhbEZlYXR1cmVQbG90KHNvYmosIGZlYXR1cmVzID0gJ2N5cDJlMV96c2NvcmUnLCBpbWFnZXMgPSAnc2xpY2UxJykKYGBgCgpUcnkgd2l0aCBSU1BPMwoKYGBge3J9CnpzY29yZSA9IChzb2JqQGFzc2F5cyRTQ1RAc2NhbGUuZGF0YVsnUlNQTzMnLF0gLSBzb2JqJFBlcmljZW50cmFsX1VDZWxsKS9zZChzb2JqJFBlcmljZW50cmFsX1VDZWxsKQpzb2JqJHJzcG8zX3pzY29yZSA8LSBzY2FsZSh6c2NvcmUpClNwYXRpYWxGZWF0dXJlUGxvdChzb2JqLCBmZWF0dXJlcyA9ICdyc3BvM196c2NvcmUnLCBpbWFnZXMgPSAnc2xpY2UxJykKYGBgCgpDb3JyZWxhdGUgYWxsIGdlbmVzIHdpdGggQ1YgYW5kIFBQIHNpZ25hdHVyZXMKCmBgYHtyfQpjdl9jb3IgPC0gYXBwbHkoc29iakBhc3NheXMkU0NUQGNvdW50cywgMSwgZnVuY3Rpb24gKHgpIGNvcih4LCB5ID0gc29iaiRQZXJpY2VudHJhbF9VQ2VsbCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1ldGhvZCA9ICJzcGVhcm1hbiIpKQpoZWFkKHNvcnQoY3ZfY29yLCBkZWNyZWFzaW5nID0gVFJVRSkpCnBwX2NvciA8LSBhcHBseShzb2JqQGFzc2F5cyRTQ1RAY291bnRzLCAxLCBmdW5jdGlvbiAoeCkgY29yKHgsIHkgPSBzb2JqJFBlcmlwb3J0YWxfVUNlbGwsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtZXRob2QgPSAic3BlYXJtYW4iKSkKaGVhZChzb3J0KHBwX2NvciwgZGVjcmVhc2luZyA9IFRSVUUpKQpgYGAKCldyaXRlIHRhYmxlCgpgYGB7cn0Kc3BhdGlhbF9jb3JzIDwtIGNiaW5kKGN2X2NvciwgcHBfY29yKQp3cml0ZS50YWJsZShzcGF0aWFsX2NvcnMsCiAgICAgICAgICAgIGZpbGUgPSAiLi9maWd1cmVzL3NwYXRpYWwvc3BhdGlhbF9nZW5lX2NvcnJlbGF0aW9ucy50c3YiLAogICAgICAgICAgICBxdW90ZSA9IEZBTFNFLAogICAgICAgICAgICBzZXAgPSAiXHQiLAogICAgICAgICAgICByb3cubmFtZXMgPSBUUlVFLAogICAgICAgICAgICBjb2wubmFtZXMgPSBUUlVFKQpgYGAKCgpTYXZlIG9iamVjdCBpZiBuZWVkZWQKCmBgYHtyfQpzYXZlUkRTKHNvYmosCiAgICAgICAgZmlsZSA9ICIuLi9zcGF0aWFsL21lcmdlZF9zcGF0aWFsX3NvYmouUkRTIikKYGBgCgoK